SQLiteは軽量で高速ですが、100万件を超える大規模データを扱うと 検索が遅い・INSERTが遅い・DataGridが固まる・DBが肥大化する といった問題が発生します。
この記事では、SQLiteで100万件以上のデータを扱うための 高速化・安定化テクニックを実務目線でまとめます。
・インデックス最適化
・ページング(LIMIT/OFFSET)
・WALモードの効果と注意点
・バルクINSERT(高速登録)
・VACUUM / ANALYZE の使い方
・FTS5(全文検索)との使い分け
・WPF DataGrid高速化との連携
1. 大規模データでSQLiteが遅くなる理由
100万件を超えると、次の問題が顕著になります。
- インデックス不足 → 全件スキャン
- JOINが重い → メモリ消費増大
- 大量INSERT → トランザクションが遅い
- DB肥大化 → I/O増加
- DataGridに全件バインド → UIフリーズ
これらを1つずつ潰していくのが最適化の基本です。
2. インデックス最適化(最重要)
大規模データで最も効くのはインデックス設計です。 WHERE句・JOIN句に使う列には必ずインデックスを貼ります。
■ 基本
CREATE INDEX idx_users_name ON Users(Name);
■ 複合インデックス
CREATE INDEX idx_orders_user_date ON Orders(UserId, OrderDate);
複合インデックスは順番が重要です。
■ インデックス確認
PRAGMA index_list('Users');
3. ページング(LIMIT/OFFSET)で全件取得を避ける
100万件を一度にSELECTすると、 UIが固まる・メモリ不足・遅延が発生します。
■ 正しいSQL
SELECT * FROM Logs
ORDER BY Id
LIMIT @limit OFFSET @offset;
1ページ100〜500件が最も安定します。
4. WALモードで読み書きを高速化
WAL(Write-Ahead Logging)モードは 読み込みと書き込みの競合を減らすため、大規模データで効果的です。
PRAGMA journal_mode = WAL;
■ 効果
- SELECTが高速化
- 書き込みロックが減る
5. バルクINSERT(高速登録)
100万件のINSERTを1件ずつ行うと非常に遅いです。 トランザクション+プリペアドステートメントで高速化します。
■ C#(Dapper)高速INSERT例
using var tran = con.BeginTransaction();
var sql = "INSERT INTO Logs (Message, CreatedAt) VALUES (@msg, @dt)";
var stmt = con.Prepare(sql);
foreach (var item in items)
{
con.Execute(stmt, new { msg = item.Message, dt = item.CreatedAt }, tran);
}
tran.Commit();
1件ずつINSERTするより10〜50倍高速になります。
6. VACUUM / ANALYZE でDB肥大化を防ぐ
■ VACUUM(DB再構築)
VACUUM;
削除が多いDBは肥大化し、遅くなります。
■ ANALYZE(統計情報更新)
ANALYZE;
インデックスの最適化に必須。
7. FTS5(全文検索)との使い分け
大量テキスト検索はLIKEでは遅いため、 FTS5(全文検索)を使うと高速化できます。
■ FTS5テーブル例
CREATE VIRTUAL TABLE LogsSearch USING fts5(
Message,
tokenize = 'unicode61'
);
ログ検索・メモ検索に最適。
8. WPF DataGrid × 大規模データの最適化
100万件をDataGridにバインドすると固まります。 以下の対策が必須です。
- 仮想化(Virtualization)ON
- ページング(100〜500件)
- 非同期読み込み(async/await)
- ObservableCollectionを使いすぎない
■ DataGridの仮想化設定
<DataGrid
EnableRowVirtualization="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingPanel.VirtualizationMode="Recycling"
/>
9. 大規模データ向けベストプラクティス
- インデックス設計が最重要
- 全件取得禁止 → ページング必須
- WALモードで読み書きを高速化
- バルクINSERTで大量登録を高速化
- VACUUM / ANALYZE を定期実行
- FTS5で全文検索を高速化
- DataGridは仮想化+非同期で表示
まとめ:SQLiteは100万件でも“設計次第で高速に動く”
- インデックスとページングで検索が高速化
- WALとバルクINSERTで書き込みが高速化
- VACUUMでDB肥大化を防ぐ
- FTS5で全文検索も高速化
- UIは仮想化で体感速度UP
「SQLiteは小規模向け」というのは誤解で、 正しい設計をすれば100万件以上でも十分高速に動作します。 この記事をベースに、あなたのアプリに最適な大規模データ戦略を構築してみてください。